package cobots.swarm.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.LinkedHashMap;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JPanel;

import cobots.swarm.agents.FollowerAgent;
import cobots.swarm.agents.LeaderAgent;
import cobots.swarm.agents.PathFollowingAgent;
import cobots.swarm.agents.Target;
import cobots.swarm.colormap.ColorMap;
import cobots.swarm.colormap.ColorMapFactory;
import cobots.swarm.main.SwarmState;
import cobots.swarm.props.PropertiesClass;

public class MainViewClass extends JPanel {

	protected Ellipse2D.Double ellis = new Ellipse2D.Double(-3,-3,6,6);

	private static final long serialVersionUID = 1L;
	
	protected float iRadius = PropertiesClass.getIradius();
	
	protected static double senseRadius = PropertiesClass.getSenseRadius();
	protected int vanishTime = PropertiesClass.getFadingRate();
	protected boolean growing = false;
	protected static  MainViewClass vis = new MainViewClass();

	protected ColorMap hotColormap = ColorMapFactory.createJetColorMap();
	public static Point2D mousePressedPoint = null;	

	protected static LinkedHashMap<Short, Point2D> lastStates = new LinkedHashMap<Short, Point2D>();
	protected static LinkedHashMap<Short, Float> timestamps = new LinkedHashMap<Short, Float>();

	protected MouseHandler interaction = new MouseHandler();

	public MainViewClass() {
		setBackground(Color.black);

		addMouseListener(new MouseAdapter() {
			
			public void mouseClicked(MouseEvent e) {
				mousePressedPoint = new Point2D.Double(e.getPoint().getX()-getWidth()/2, (getHeight()-e.getPoint().getY())-getHeight()/2);
				interaction.mouseClicked(mousePressedPoint, e.getButton(), e.isControlDown());
			}
		});


	}

	

	public static void updatePartialVisualization() {
		Vector<Short> toRemove = new Vector<Short>();

		for (short s : lastStates.keySet()) {
			Point2D pt = lastStates.get(s);
			for (LeaderAgent l : SwarmState.leaders.values()) {
				if (pt.distance(l) < senseRadius) {
					toRemove.add(s);
				}
			}
		}

		for (Short s : toRemove)
			lastStates.remove(s);

		for (FollowerAgent s : SwarmState.followers.values()) {
			for (LeaderAgent l : SwarmState.leaders.values()) {
				if (s.distance(l) < senseRadius) {
					timestamps.put(s.getId(), SwarmState.currentTime);
					lastStates.put(s.getId(), new Point2D.Double(s.getX(),s.getY()));
					break;
				}
			}
		}

			}


	public void paint(Graphics arg0) {
		arg0.setColor(Color.black);
		arg0.fillRect(0, 0, getWidth(), getHeight()); //Remember 0,0 is the rightmost coordinate

		Graphics2D g = (Graphics2D)arg0;
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
		g.setColor(Color.green);
		g.drawString("Time: "+SwarmState.currentTime, 20, 20);		
		g.translate(getWidth()/2, getHeight()/2);
		g.scale(1, -1);
		g.setColor(Color.green);

		
		for (Target a : SwarmState.targets.values()) {

			float targetAge = (SwarmState.currentTime-SwarmState.getTargetAge(a.getId()))/1000;//client.getTargetAge((int)a.getId()) / 1000;
			if (targetAge > 1) 
				targetAge = 1;
			g.setColor(new Color(targetAge, 1-targetAge, 0f));

			double r = a.getMass() * 10;
			g.fill(new Rectangle2D.Double(a.getX()-r, a.getY()-r, r*2, r*2));                     
		}   

		for (FollowerAgent s : SwarmState.followers.values()) {

			if (!lastStates.containsKey(s.getId()))
				continue;

			float certainty = (SwarmState.currentTime-timestamps.get(s.getId()))/vanishTime;
			if (certainty > 1) certainty = 1;

			certainty = 1-certainty;
			Color c = hotColormap.getColor(certainty).brighter().brighter();


			if (s.getLeaderId() == -1)
				g.setColor(c.darker());
			else
				g.setColor(c.brighter().brighter());

			Point2D pt = lastStates.get(s.getId());
		
			if (pt == null)
				break;
			g.translate(pt.getX(), pt.getY());
			g.fill(ellis);
			g.translate(-pt.getX(), -pt.getY());

		}

		for (LeaderAgent s : SwarmState.leaders.values()) {
			
			if (s instanceof PathFollowingAgent) {
				g.setColor(Color.cyan);
				Vector<Point2D> path = SwarmState.getPath(s.getId());
				GeneralPath p = new GeneralPath();
				p.moveTo(path.firstElement().getX(), path.firstElement().getY());				
				for (int i = 1; i < path.size(); i++) {
					p.lineTo(path.get(i).getX(), path.get(i).getY());					
				}
				p.closePath();
				g.draw(p);
				
				for (int i = 0; i < path.size(); i++) {
					g.fill(new Ellipse2D.Double(path.get(i).getX()-2, path.get(i).getY()-2, 6, 6));
				}
			}
			
			
			if (interaction.selectedLeader == s.getId()) {
				if (growing)
					interaction.attractionRadius = iRadius + (System.currentTimeMillis()-interaction.clickTime) * 0.05f;
				g.setColor(Color.yellow);
				g.draw(new Ellipse2D.Double(s.getX()-interaction.attractionRadius, s.getY()-interaction.attractionRadius, interaction.attractionRadius*2, interaction.attractionRadius*2));
			}

			if (s.getTargetId() == -1)
				g.setColor(Color.white.darker().darker());
			else if (interaction.selectedLeader == s.getId())
				g.setColor(Color.green);
			else
				g.setColor(Color.white);
			
			g.fill(new Ellipse2D.Double(s.getX()-5, s.getY()-5, 14, 14));
			
		}	

	}

	public static void main(String[] args) {
		vis = new MainViewClass();

		JFrame frame = new JFrame("Cobots Research Group");
		frame.setLayout(new BorderLayout());
		frame.getContentPane().add(vis);
		frame.setSize(800, 600);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);

		new Thread() {
			public void run() {
				while (true) {
					try {
						vis.repaint();			
						Thread.sleep(10);						
					}
					catch (Exception e) {                      
						e.printStackTrace();
						System.exit(1);
					}
				}
			};
		}.start();	
	}
}
